package org.xinjiang.data.migration.common.mapstruct.convert;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Throwables;
import org.mapstruct.DecoratedWith;
import org.mapstruct.Mapper;
import org.mapstruct.Qualifier;
import org.mapstruct.TargetType;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * JSON转换
 *
 * @author wenjie
 * @date 2022/11/25
 */
@Qualified.Mapper
@DecoratedWith(Qualified.QualifiedDecorator.class)
@Mapper(componentModel = "spring")
public interface Qualified {

    @JsonValue
    default <T> T fromJson(String s, @TargetType Class<T> type) {
        throw new UnsupportedOperationException();
    }

    @JsonValue
    default <T> String json(T s) {
        throw new UnsupportedOperationException();
    }

    /**
     * 用于处理特殊的枚举值,该类必须有个 <code>static V fromInteger(Integer i);</code> 方法
     */
    interface IntegerHolder {

        Integer asInteger();

    }

    @Qualifier
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.CLASS)
    @interface Mapper {

    }

    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.CLASS)
    @interface IntegerValue {

    }

    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.CLASS)
    @interface JsonValue {

    }

    abstract class QualifiedDecorator implements Qualified {

        @Resource
        ObjectMapper objectMapper;

        @Override
        public <T> T fromJson(String s, @TargetType Class<T> type) {
            if (s == null) {
                return null;
            }
            try {
                return objectMapper.readValue(s, type);
            } catch (IOException e) {
                throw Throwables.propagate(e);
            }
        }

        @Override
        public <T> String json(T s) {
            if (s == null) {
                return null;
            }
            try {
                return objectMapper.writeValueAsString(s);
            } catch (JsonProcessingException e) {
                throw Throwables.propagate(e);
            }
        }

    }

}
